﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using BungieNode;
using NUnit.Framework;

namespace BungieNodeUnitTests
{
    [TestFixture]
    public class BungieNodeTests
    {
        public class TestData
        {
            static public Node ListHead;
            static public List<Node> Nodes;
            static TestData()
            {
                Node nodeE = new Node { Tag = "E" };
                Node nodeD = new Node { Tag = "D", Next = nodeE, Reference = nodeE };
                Node nodeC = new Node { Tag = "C", Next = nodeD, Reference = nodeE };
                Node nodeB = new Node { Tag = "B", Next = nodeC };
                Node nodeA = new Node { Tag = "A", Next = nodeB, Reference = nodeD };

                ListHead = nodeA;
                //manually order nodes
                Nodes = new List<Node> { nodeA, nodeB, nodeC, nodeD, nodeE };
            }
        }

        public class TheGetEnumeratorMethod
        {
            [Test]
            public void NodesAreInOrder()
            {
                Assert.That(TestData.ListHead, Is.EquivalentTo(TestData.Nodes));
            }
        }

        public class TheDuplicateListMethod
        {
            [Test]
            public void OrderIsMaintained()
            {
                Node duplicateListHead = Node.DuplicateList(TestData.ListHead);
                var duplicateTags = duplicateListHead.Select(node => node.Tag);
                var originalTags = TestData.Nodes.Select(node => node.Tag);
                Assert.That(duplicateTags, Is.EquivalentTo(originalTags));
            }

            [Test]
            public void ReferencesAreMaintained()
            {
                Node duplicateListHead = Node.DuplicateList(TestData.ListHead);
                var duplicateTags = duplicateListHead.Select(GetReferenceTag);
                var originalTags = TestData.Nodes.Select(GetReferenceTag);
                Assert.That(duplicateTags, Is.EquivalentTo(originalTags));
            }

            private string GetReferenceTag(Node node)
            {
                if (node.Reference == null)
                {
                    return null;
                }
                else
                {
                    return node.Reference.Tag;
                }
            }

            [Test]
            public void ContainsNoCrossReferences()
            {
                Node duplicateListHead = Node.DuplicateList(TestData.ListHead);

                var duplicateReferences = duplicateListHead.Where(node => node.Reference != null).Select(node => node.Reference);
                var duplicatesNodesAndDuplicateReferences = duplicateListHead.Concat(duplicateReferences);

                //assert that the duplicate list (and its references) don't have references to the original list
                Assert.That(duplicatesNodesAndDuplicateReferences.Intersect(TestData.Nodes, EqualityComparer<Node>.Default).Count(), Is.EqualTo(0));
            }
        }
    }
}
